/*
 * TerminosEnMemoria.cpp
 *
 *  Created on: 27/11/2011
 *      Author: putaro
 */

#include "TerminosEnMemoria.h"
#include <cstring>
/*
 * Pre:-
 * Post: Se ha creado una instancia de la clase lista para ser utilizada.
*/
TerminosEnMemoria::TerminosEnMemoria(const string & directorioArchivosParser) {
	this -> tamBufferTerminos = 0;
	this -> cantidadTerminos = 0;
	string rutaArchivo(directorioArchivosParser);
	rutaArchivo.append("/");
	rutaArchivo.append(ARCHIVO_PARSER1);
	this->archivo.open(rutaArchivo.c_str(),ios::in | ios::binary);
}

/*
 * Pre: La instancia ha sido creada.
 * Post: Se ha cargado una nueva serie de terminos en memoria.
 */
bool TerminosEnMemoria::cargarNuevosTerminos(){
	bool retorno = false;
	//limpieza terminos anteriores
	this -> tamBufferTerminos = 0;
	this -> cantidadTerminos = 0;
	this -> bufferTerminos.clear();
	this -> datosTerminos.clear();
	if( (archivo.is_open()) && (!archivo.eof())){

		bool fin = false;
		T_RegistroTerminos registroEntrada;
		this->archivo.read(reinterpret_cast<char *>(&registroEntrada),
							  sizeof(T_RegistroTerminos));
		//carga de terminos en memoria
		while( !archivo.eof() && (!fin)){
			T_RegistroTerminosEnMemoria registroMemoria;
			retorno = true;
			//obtención de datos
			unsigned int longitud = 0;
			unsigned char* buffer = NULL;
			registroMemoria.documento= 0;
			registroMemoria.offset = 0;

			registroMemoria.documento = registroEntrada.documento;
			registroMemoria.offset = cantidadTerminos;
			longitud = registroEntrada.longitudTermino +1;
			buffer = new unsigned char[longitud];
			memset(buffer,0,longitud);
			archivo.read(reinterpret_cast<char *>(buffer),registroEntrada.longitudTermino);
			//almacenamiento de datos en memoria
			string cadena(reinterpret_cast<char *>(buffer));
			this -> bufferTerminos.push_back(cadena);
			this -> datosTerminos.push_back(registroMemoria);
			delete[](buffer);
			buffer = NULL;
			cantidadTerminos++;
			tamBufferTerminos+= longitud;
			//lectura del siguiente dato a cargar
			if(tamBufferTerminos < TAM_MAX_APROX_BUFFER_TERMINOS){
				this->archivo.read(reinterpret_cast<char *>(&registroEntrada),
										  sizeof(T_RegistroTerminos));
			} else {
				fin = true;
			}
		}
	}
	return retorno;
}

/*
 * Pre: Se ha creado la instancia.
 * Post: La instancia ha sido destruido liberando los recursos asociados.
*/
TerminosEnMemoria::~TerminosEnMemoria() {
	this -> archivo.close();
	this -> datosTerminos.clear();
	this -> bufferTerminos.clear();
}

/*
 * Pre: La instancia ha sido creada.
 * Post: Se ha ordenado por quicksort los datos contenidos en la instancia.
 * Dicho ordenamiento consiste en la reorganización del atributo datosTerminos
 * de menor a mayor.
 * Se ordena por termino y documento.
 */
void TerminosEnMemoria::quickSort(){
	if(this->cantidadTerminos>0){
		this->quickSort(0 , this -> cantidadTerminos);
	}
}

/*
 * Pre: La instancia ha sido creada.
 * Post: Se ha ordenado por quicksort los datos contenidos en la instancia.
 * Dicho ordenamiento consiste en la reorganización del atributo datosTerminos
 * de menor a mayor.
 * Se ordena por termino y documento.
 */
void TerminosEnMemoria::quickSort(const int primero, const int ultimo){
	int pivote;
	if(primero < ultimo){
	   pivote=colocar(primero, ultimo);
	   quickSort(primero, pivote-1);
	   quickSort(pivote+1, ultimo);
	}
}

int TerminosEnMemoria::colocar(const int primero, const int ultimo){
	 int pivote;
	 //valores en pivote
	 T_RegistroTerminosEnMemoria valorPivote;
	 T_RegistroTerminosEnMemoria temp;
	 pivote = primero;
	 //obtengo valores en pivote;
	 valorPivote.documento = datosTerminos[pivote].documento;
	 valorPivote.offset=datosTerminos[pivote].offset;
	 for (int i = primero + 1; i <= ultimo; i++){
		 if (isMenor(i , valorPivote)){
			 pivote++;
			 temp.documento = datosTerminos[i].documento;
			 temp.offset = datosTerminos[i].offset;
			 datosTerminos[i].documento = datosTerminos[pivote].documento;
			 datosTerminos[i].offset = datosTerminos[pivote].offset;
			 datosTerminos[pivote].documento = temp.documento;
			 datosTerminos[pivote].offset = temp.offset;
		 }
	 }
	 temp.documento = datosTerminos[primero].documento;
	 temp.offset = datosTerminos[primero].offset;
	 datosTerminos[primero].documento = datosTerminos[pivote].documento;
	 datosTerminos[primero].offset = datosTerminos[pivote].offset;
	 datosTerminos[pivote].documento = temp.documento;
	 datosTerminos[pivote].offset = temp.offset;
	 return pivote;
}
/*
 *
 * Returns: True si el primero menor que el segundo
 */
bool TerminosEnMemoria::isMenor(const unsigned posicionEnDatos ,
								const T_RegistroTerminosEnMemoria &registro){
	bool retorno = false;
	int comparacionTerminos = bufferTerminos[datosTerminos[posicionEnDatos].offset].compare(
							bufferTerminos[registro.offset]);
	if(comparacionTerminos == 0){
		retorno = datosTerminos[posicionEnDatos].documento < registro.documento;
	}else{
		retorno = comparacionTerminos < 0;
	}
	return retorno;
}


unsigned int TerminosEnMemoria::cantidadDeTerminos(){
	return this->cantidadTerminos;
}

vector<string> TerminosEnMemoria::getBufferTerminos(){
	return this->bufferTerminos;
}

vector<registroTerminosEnMemoria> TerminosEnMemoria::getDatosTerminos(){
	return this->datosTerminos;
}

